package training.bms.persistence;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang.StringUtils;

import training.bms.business.Blog_;
import training.bms.business.Post;
import training.bms.business.PostSearchOptions;
import training.bms.business.Post_;
import training.framework.persistence.AbstractEntityDao;

public class PostDao extends AbstractEntityDao<Integer, Post, PostSearchOptions>{

	public PostDao() {
		super(EntityManagerFactorySingleton.FACTORY, Post.class);
	}

	@Override
	protected Order toOrder(CriteriaBuilder builder, Root<Post> root) {
		return builder.asc(root.get(Post_.title));
	}

	@Override
	protected Predicate toPredicate(CriteriaBuilder builder, Root<Post> root,
			PostSearchOptions options) {
		Predicate blogPredicate;
		Integer blogIdentifier = options.getBlogIdentifier(); 
		if (blogIdentifier == null || blogIdentifier == 0) {
			blogPredicate = builder.conjunction();
		} else {
			blogPredicate = builder.equal(
				// post.blog.identifier
				root.get(Post_.blog).get(Blog_.identifier),
				blogIdentifier
			);
		}

		Predicate titlePredicate;
		String postTitle = options.getTitle();
		if (StringUtils.isBlank(postTitle)) {
			titlePredicate = builder.conjunction();								
		} else {
			titlePredicate = builder.like(
				builder.lower(root.get(Post_.title)), 
				toLikeParameter(postTitle)
			);
		}
			
		Predicate contentPredicate;
		String postDescription = options.getContent();
		if (StringUtils.isBlank(postDescription)) {
			contentPredicate = builder.conjunction();
		} else {
			contentPredicate = builder.like(
				builder.lower(root.get(Post_.content)), 
				toLikeParameter(postDescription)
			);				
		}
		
		Predicate predicate = builder.and(blogPredicate, titlePredicate, contentPredicate);
		return predicate;
	}	
	/*public void insertPost(final Post post) {
		AbstractManagerTemplate template = new AbstractManagerTemplate() {			
			@Override
			protected void execute(EntityManager manager) {
				manager.persist(post);
			}
		};
		template.execute();
	}
	
	public List<Post> selectPost(PostSearchOptions options) {
		return selectPostCriteria(options);
	}
	
	public int selectPostCount(PostSearchOptions options) {				
		EntityManager manager = null;
		try {
			manager =  EntityManagerFactorySingleton.FACTORY.createEntityManager();

			CriteriaBuilder builder = manager.getCriteriaBuilder();
			CriteriaQuery<Long> criteriaQuery = builder.createQuery(Long.class);
			Root<Post> root = criteriaQuery.from(Post.class);
			
			criteriaQuery.select(builder.count(root));
			criteriaQuery.where(toPredicate(builder, root, options));
			
			TypedQuery<Long> query = manager.createQuery(criteriaQuery);
			
			Long result = query.getSingleResult();
			return result.intValue();
		} finally {
			if (manager != null) {
				try {
					manager.close();
				} catch (RuntimeException e) {}
			}
		}						
	}
	
	private Predicate toPredicate(CriteriaBuilder builder, Root<Post> root, PostSearchOptions options) {
		Predicate blogPredicate;
		Integer blogIdentifier = options.getBlogIdentifier(); 
		if (blogIdentifier == null || blogIdentifier == 0) {
			blogPredicate = builder.conjunction();
		} else {
			blogPredicate = builder.equal(
				// post.blog.identifier
				root.get(Post_.blog).get(Blog_.identifier),
				blogIdentifier
			);
		}

		Predicate titlePredicate;
		String postTitle = options.getTitle();
		if (StringUtils.isBlank(postTitle)) {
			titlePredicate = builder.conjunction();								
		} else {
			titlePredicate = builder.like(
				builder.lower(root.get(Post_.title)), 
				toLikeParameter(postTitle)
			);
		}
			
		Predicate contentPredicate;
		String postDescription = options.getContent();
		if (StringUtils.isBlank(postDescription)) {
			contentPredicate = builder.conjunction();
		} else {
			contentPredicate = builder.like(
				builder.lower(root.get(Post_.content)), 
				toLikeParameter(postDescription)
			);				
		}
		
		Predicate predicate = builder.and(blogPredicate, titlePredicate, contentPredicate);
		return predicate;
	}
	
	public List<Post> selectPostCriteria(PostSearchOptions options) {
		EntityManager manager = null;
		try {
			manager =  EntityManagerFactorySingleton.FACTORY.createEntityManager();

			CriteriaBuilder builder = manager.getCriteriaBuilder();
			CriteriaQuery<Post> criteriaQuery = builder.createQuery(Post.class);
			Root<Post> root = criteriaQuery.from(Post.class);
						
			criteriaQuery.select(root);
			criteriaQuery.where(toPredicate(builder, root, options));
			Order order = builder.asc(root.get(Post_.title));
			criteriaQuery.orderBy(order);
			
			TypedQuery<Post> query = manager.createQuery(criteriaQuery);
			if (options.getFirstResult() != null) {
				query.setFirstResult(options.getFirstResult());
			}
			if (options.getMaxResults() != null) {
				query.setMaxResults(options.getMaxResults());
			}
			
			List<Post> result = query.getResultList();
			return result;
		} finally {
			if (manager != null) {				
				try {
					manager.close();
				} catch (RuntimeException e) {}
			}
		}				
	}	
	
	private String toLikeParameter(String parameter) {
		return "%" + parameter.toLowerCase().trim() + "%";
	}

	public void updatePost(final Post post) {
		AbstractManagerTemplate template = new AbstractManagerTemplate() {			
			@Override
			protected void execute(EntityManager manager) {
				manager.merge(post);
			}
		};
		template.execute();
	}
	
	public void deletePost(final Post post) {
		new ManagerUtil().execute(
			new ManagerStrategy() {				
				@Override
				public void execute(EntityManager manager) {
					Post databasePost = manager.find(Post.class, post.getIdentifier());
					manager.remove(databasePost);					
				}
			}
		);
	}*/
}
